# coding: utf-8

# -------------------------------------------------------------------------------
# Name:         testsuite.py
# Description:  
# Author:       XiangjunZhao
# EMAIL:        2419352654@qq.com
# Date:         2019/11/20 13:56
# -------------------------------------------------------------------------------
from io import BytesIO

import pandas as pd
from django.http import StreamingHttpResponse
from rest_framework import status
from rest_framework.generics import DestroyAPIView
from rest_framework.mixins import UpdateModelMixin
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ReadOnlyModelViewSet, GenericViewSet

from QAPlatform.mixins import CustomCreateModelMixin
from apps.BasicAuthService.models import Role
from apps.CeleryScheduledTaskService.HttpAutoTestService.testsuite_task import batch_exec_testsuite
from apps.HttpAutoTestService.filters import TestsuiteFilter, TestsuiteNameFilter
from apps.HttpAutoTestService.models import Testsuite, Testsuite2Testcase, TestsuiteSet2Testsuite
from apps.HttpAutoTestService.serializers import TestsuiteListSerializer, TestsuiteSerializer, \
    TestsuiteNameListSerializer
from apps.HttpAutoTestService.utils.export_testsuite_task import export_testsuite
from utils.common import get_version

__all__ = ['TestsuiteNameListViewSet', 'TestsuiteListViewSet', 'TestsuiteViewSet', 'TestsuiteBatchDestroyAPIView',
           'TestsuiteBatchExecAPIView', 'TestsuiteCopyAPIView', 'TestsuiteExportAPIView']


class TestsuiteNameListViewSet(ReadOnlyModelViewSet):
    """
    场景名称列表
    """
    serializer_class = TestsuiteNameListSerializer
    filter_class = TestsuiteNameFilter
    pagination_class = None

    def get_queryset(self):
        user = self.request.user
        testsutes = Testsuite.objects.filter(is_deleted=False).values('id', 'name')
        if not Role.objects.filter(code='SUPERADMIN', user=user, is_deleted=False):
            testsutes = testsutes.filter(project__members=user).distinct()
        return testsutes


class TestsuiteListViewSet(ReadOnlyModelViewSet):
    """
    场景列表
    """
    serializer_class = TestsuiteListSerializer
    filter_class = TestsuiteFilter

    def get_queryset(self):
        user = self.request.user
        testsutes = Testsuite.objects.filter(is_deleted=False)
        if not Role.objects.filter(code='SUPERADMIN', user=user, is_deleted=False):
            testsutes = testsutes.filter(project__members=user).distinct()
        return testsutes


class TestsuiteViewSet(CustomCreateModelMixin, UpdateModelMixin, GenericViewSet):
    """
    场景创建、更新
    """
    queryset = Testsuite.objects.filter(is_deleted=False)
    serializer_class = TestsuiteSerializer


class TestsuiteBatchDestroyAPIView(DestroyAPIView):
    """
    场景批量删除
    """

    def delete(self, request, *args, **kwargs):
        unbundle = request.data.get('unbundle')  # 解绑 true：删除场景并解绑与场景集的关系，false：只删除未关联场景集的场景
        testsuite_ids = request.data.get('testsuites')
        if unbundle:
            # 删除场景并解绑与场景集的关系
            # 1、删除场景
            Testsuite.objects.filter(id__in=testsuite_ids).update(is_deleted=True)
            # 2、解绑场景与用例的关联
            Testsuite2Testcase.objects.filter(testsuite_id__in=testsuite_ids).delete()
            # 3、解绑场景与场景集的关联
            TestsuiteSet2Testsuite.objects.filter(testsuite_id__in=testsuite_ids).delete()
        else:
            # 只删除未关联场景集的场景
            Testsuite.objects.filter(id__in=testsuite_ids).exclude(
                id__in=TestsuiteSet2Testsuite.objects.filter(testsuite_id__in=testsuite_ids).values_list('testsuite_id',
                                                                                                         flat=True).distinct()).update(
                is_deleted=True)
        return Response(status=status.HTTP_204_NO_CONTENT)


class TestsuiteBatchExecAPIView(APIView):
    """
    场景批量执行
    """

    def post(self, request, *args, **kwargs):
        user = request.user
        data = request.data
        testsuites = data.get('testsuites')
        version = get_version()
        # 以异步方式执行
        batch_exec_testsuite.delay(testsuites=testsuites, executor_id=user.id, is_periodictask=False, version=version)
        # 以阻塞方式执行
        # batch_exec_testsuite(testsuites=testsuites, executor_id=user.id, is_periodictask=False, version=version)
        return Response(status=status.HTTP_200_OK, data='程序正在后台运行中,请稍后查看结果……', content_type='application/json')


class TestsuiteCopyAPIView(APIView):
    """
    复制场景
    """

    def post(self, request, *args, **kwargs):
        user = request.user
        data = request.data
        testsuite_id = data.get('id')
        name = data.get('name')
        testsuite = Testsuite.objects.get(id=testsuite_id)
        testsuite_dict = {
            'name': name,
            'project_id': testsuite.project_id,
            'global_variables': testsuite.global_variables,
            'level': testsuite.level,
            'remark': testsuite.remark,
            'creator_id': user.id,
            'modifier_id': user.id,
        }
        new_testsuite = Testsuite(**testsuite_dict)

        testsuite2testcase_list = Testsuite2Testcase.objects.filter(testsuite_id=testsuite_id).values(
            'testcase_id', 'testcase_name', 'url', 'request_params', 'headers',
            'request_data_type', 'request_data', 'ext_method', 'ext_method_name',
            'expect_result', 'type', 'is_execute', 'loop_count', 'sort'
        )
        new_testsuite2testcase_list = []
        for testsuite2testcase_dict in testsuite2testcase_list:
            testsuite2testcase_dict.update({
                'testsuite_id': new_testsuite.id,
                'testsuite_name': new_testsuite.name
            })
            testsuite2testcase = Testsuite2Testcase(**testsuite2testcase_dict)
            new_testsuite2testcase_list.append(testsuite2testcase)

        new_testsuite.save()
        Testsuite2Testcase.objects.bulk_create(new_testsuite2testcase_list)
        return Response(status=status.HTTP_201_CREATED, content_type='application/json')


class TestsuiteExportAPIView(APIView):
    """
    导出测试场景
    """

    def post(self, request, *args, **kwargs):
        data = request.data
        testsuite_ids = data.get('testsuite_ids')
        testsuite_list = Testsuite.objects.filter(id__in=testsuite_ids, is_deleted=False)
        bio = BytesIO()
        with pd.ExcelWriter(bio, engine='xlsxwriter') as excel_writer:
            for index, testsuite in enumerate(testsuite_list, start=1):
                project_name = testsuite.project.name
                testsuite_name = testsuite.name
                summary_info = f'项目名称：{project_name}\n场景名称：{testsuite_name}\n说明：如果需要将此导出数据再次导入系统中，请删除此行数据，再在接口列表中通过【导入接口|用例】功能导入'
                # excel的sheet页名称最多31个字符
                sheet_name = f'Sheet{index}'
                # 导出场景用例数据
                export_testsuite(excel_writer=excel_writer, sheet_name=sheet_name, testsuite=testsuite, start_row=1)
                # 填充场景概要信息
                sheet = excel_writer.sheets[sheet_name]
                sheet.merge_range(first_row=0, first_col=0, last_row=0, last_col=9, data=summary_info)
                sheet.set_row(row=0, height=60)
            excel_writer.save()
            excel_writer.close()
        bio.seek(0)
        response = StreamingHttpResponse(bio)
        response['Content-Type'] = 'application/octet-stream'
        response['Content-Disposition'] = 'attachment;filename="测试场景导出.xlsx"'
        return response
